#include "Trans2.h"

Trans2_T* Trans2_t;

//************************************
// Method:    	CALCU_SAMA					//< SAMA运算函数
// Programmer:  duan
// Time:		2019/06/24
// Returns:   	bool						//< 成功：true；失败：false
// Parameter: 	Model_Base_t * arg			//< 模块参数结构体指针
// Parameter: 	float dt					//< 运算周期
// Parameter: 	bool * DI					//< 数字量输入值数组指针
// Parameter: 	bool * DO					//< 数字量输出值数组指针
// Parameter: 	bool * AI					//< 模拟量输入值数组指针
// Parameter: 	bool * AO					//< 模拟量输出值数组指针
//************************************
bool CALCU_SAMA(Trans2)(Model_Base_t* arg, float dt, bool* DI, bool* DO, float* AI, float* AO)
{
#define min(x, y) {\
		typeof(x) _min1 = (x);\
		typeof(y) _min2 = (y);\
		(void) (&_min1 == &_min2);\
		_min1 < _min2 ? _min1 : _min2;}

#define max(x, y) {\
		typeof(x) _max1 = (x);\
		typeof(y) _max2 = (y);\
		(void) (&_max1 == &_max2);\
		_max1 > _max2 ? _max1 : _max2; }
	/****************变量定义区开始**************/
	
	int i = 0;
	/*<<<<<定义输入变量>>>>>*/
	float PV1_Value;
	float PV2_Value;

	/*<<<<<定义输出变量>>>>>*/
	float AO_Value = 0;
	bool Alert_Sig;
	ChangeAM MRE;

	/*<<<<<定义参数变量>>>>>*/
	Trans2_WorkMode Work_Mode;
	Trans2_OutMode Out_Mode;

	float Alert_Range;
	float Alert_Dead;
	float Safe_OutValue;
	
	/*<<<<<定义中间变量>>>>>*/
	bool* AIfLink[2];					//< 记录模拟量输入的有效测点

	/****************变量定义区结束**************/

	NAME(Trans2)* Obj = (NAME(Trans2)*)arg;

	/****************变量赋值**************/
	/*<<<<<输入变量赋值>>>>>*/
	PV1_Value = AI[0];
	PV2_Value = AI[1];

	/*<<<<<参数变量赋值>>>>>*/
	Work_Mode = Obj->Par.Work_Mode;
	Out_Mode = Obj->Par.Out_Mode;
	Alert_Range = Obj->Par.Alert_Range;
	Alert_Dead = Obj->Par.Alert_Dead;
	Safe_OutValue = Obj->Par.Safe_OutValue;

	/*<<<<<中间变量赋值>>>>>*/
	for (i = 0; i < 2; i++)
		AIfLink[i] = &(Obj->Sta.AIfLink[i]);

	/**************变量赋值结束************/

	/********************************************/
	/**************算法功能实现开始**************/
	/********************************************/
	if (AIfLink[0][0] == true)										//< duan0828
	{
		if (*(Obj->Base.In.AI_Pin_QualityInfo[0]) == true)
			AIfLink[0][0] = false;
	}

	if (AIfLink[1][0] == true)
	{
		if (*(Obj->Base.In.AI_Pin_QualityInfo[1]) == true)
			AIfLink[1][0] = false;
	}
	
	if (Work_Mode == Trans2_PV1_Out)								//< 工作方式为PV1或PV2,只有当输入的点为好点时，按照指定的方式输出，否则自动切换到自动工作方式
	{
		if (AIfLink[0][0] == false)
			Work_Mode = Trans2_AUTO;
		else
		{
			AO_Value = PV1_Value;
			Alert_Sig = false;
			MRE = Hold;
		}
	}

	if (Work_Mode == Trans2_PV2_Out)
	{
		if (AIfLink[1][0] == false)
			Work_Mode = Trans2_AUTO;
		else
		{
			AO_Value = PV2_Value;
			Alert_Sig = false;
			MRE = Hold;
		}
	}

	if (Work_Mode == Trans2_AUTO)										//< 工作方式为自动
	{
		if (AIfLink[0][0] == true && AIfLink[1][0] == false)			//< PV1是好点
		{
			AO_Value = PV1_Value;
			Alert_Sig = true;
			MRE = Change_MAN;											//< duan0712 待考虑
		}
		else if (AIfLink[0][0] == false && AIfLink[1][0] == true)		//< PV2是好点
		{
			AO_Value = PV2_Value;
			Alert_Sig = true;
			MRE = Change_MAN;											//< duan0712 待考虑
		}


		//< duan0625 两个点都是好点，如果两者偏差超过Range，则输出为安全值SafeV，变送器报警信号ALM为真，变送器手动信号MRE为真
		//<						  如果两者偏差没有超过Range，则输出随OutMode=0或1或2，取平均或低选或高选。。
		else if (AIfLink[0][0] == true && AIfLink[1][0] == true)
		{
			if (fabs(PV1_Value - PV2_Value) >= Alert_Range + Alert_Dead)
			{
				AO_Value = Safe_OutValue;
				Alert_Sig = true;
				MRE = Change_MAN;
			}
			else
			{
				if (Out_Mode == Average)
					AO_Value = (PV1_Value + PV2_Value) / 2;
				else if (Out_Mode == Max)
					AO_Value = (max(PV1_Value, PV2_Value));
				else if (Out_Mode == Min)
					AO_Value = (min(PV1_Value, PV2_Value));
				
				Alert_Sig = false;
				MRE = Hold;
			}
		}
		else															//< 两个点都是坏点，则输出保持不变，报警信号ALM为真，切手动信号MRE为真。
		{
			Alert_Sig = true;
			MRE = Change_MAN;
		}
	}

	/*for (i = 0; i < Obj->Base.IO_Num.AI_Num; i++)						//< duan0828 内存错误
	{
		if (*(Obj->Base.In.AI_Pin_QualityInfo[i]) == true)
			Obj->Sta.AIfLink[i] = false;
	}*/

	/********************************************/
	/**************算法功能实现结束**************/
	/********************************************/
	
	/****************运算结果输出**************/
	AO[0] = AO_Value;
	DO[0] = Alert_Sig;
	DO[1] = MRE;
	
	/**************运算结果输出完毕************/
	return true;

#undef max
#undef min
}



//************************************
// Method:    	BCPARA						//< 广播SAMA参数变量函数（无参数需要广播的模块直接将BCPara函数设置为NULL即可）
// Programmer:  duan
// Time:		2019/06/24
// Returns:   	int							//< 成功：返回打包字节个数；失败：返回0
// Parameter: 	Model_Base_t * arg			//< 模块参数结构体指针
// Parameter: 	void ** Data				//< 广播SAMA参数的数据包的指针
//************************************
int BC_PARA(Trans2)(Model_Base_t* arg, void** Data)
{
	NAME(Trans2)* Obj = (NAME(Trans2)*)arg;
	BC_PARA_PUBLIC(Obj);
	return 0;
}



//************************************
// Method:    	BAK_STA						//< 备份SAMA运算中间参数
// Programmer:  duan
// Time:		2019/06/24
// Returns:   	int							//< 成功：返回打包字节个数；失败：返回0
// Parameter: 	Model_Base_t * arg			//< 指定模块类型链表的指针
// Parameter: 	void ** Data				//< 存放数据包当前指针位置的地址
//************************************
int BAK_STA(Trans2)(Model_Base_t* arg, void** Data)
{
	NAME(Trans2)* Obj = (NAME(Trans2)*)arg;
	BAK_STA_PRIVATE(Obj);
	return 0;
}



//************************************
// Method:    	ANA_STA						//< 解析备份的SAMA运算中间参数
// Programmer:  duan
// Time:		2019/06/24
// Returns:   	int							//< 成功：返回解析字节个数；失败：返回0
// Parameter: 	Model_Base_t * arg			//< 模块参数结构体指针
// Parameter: 	void ** Data				//< 存放数据包当前指针位置的地址
//************************************
int ANA_STA(Trans2)(Model_Base_t* arg, void** Data)
{
	NAME(Trans2)* Obj = (NAME(Trans2)*)arg;
	ANA_STA_PRIVATE(Obj);
	return 0;
}



//************************************
// Method:    	CHANGE_PAR				//< 在线修改模块参数函数
// Programmer:  duan
// Time:		2019/06/24
// Returns:   	int						//< 读取字节长度计数值
// Parameter: 	Model_Base_t* arg		//< 指定模块类型链表的指针
// Parameter: 	void** Data				//< 存放数据包当前指针位置的地址
//************************************
int CHANGE_PAR(Trans2)(Model_Base_t* arg, void** Data)
{
	int _iLen = 0;
	MEMREAD(((NAME(Trans2)*)arg)->Par, Data[0]);
	return _iLen;
}



//************************************
// Method:    	INIT_STAPAR					//< 初始化模块运算中间参数
// Programmer:  duan
// Time:		2019/06/24
// Parameter: 	Model_Base_t* arg			//< 模块参数结构体指针
//************************************
void INIT_STAPAR(Trans2)(Model_Base_t* arg)
{
	int i;

	NAME(Trans2)* name = (NAME(Trans2)*)arg;
	/****************初始化中间变量结构体**************/
	memset(&(name->Sta), 0, sizeof(name->Sta));
	/**************初始化中间变量结构体结束************/

	/****************对中间变量结构体的相关参数进行赋值**************/
	for (i = 0; i < name->Base.IO_Num.AI_Num; i++)
	{
		if (name->Base.In.AI_Pin_ID[i] > 0)
		{
			name->Sta.AIfLink[i] = true;
		}
	}
	/**************对中间变量结构体的相关参数进行赋值结束************/
}
